Skip to content

salsa20: SIMD-accelerated backends via fearless_simd#576

Open
paddor wants to merge 1 commit into
RustCrypto:masterfrom
paddor:salsa20-simd
Open

salsa20: SIMD-accelerated backends via fearless_simd#576
paddor wants to merge 1 commit into
RustCrypto:masterfrom
paddor:salsa20-simd

Conversation

@paddor

@paddor paddor commented Jul 17, 2026

Copy link
Copy Markdown
  • SIMD-accelerated Salsa20/XSalsa20 via fearless_simd (SSE2/AVX2/NEON)
  • Two backends: Backend4 (4 parallel blocks, 128-bit) and Backend8
    (8 parallel blocks, 256-bit), selected at runtime by lane count
  • HSalsa20 uses diagonal SIMD layout (all 4 quarter rounds in one
    u32x4 instruction sequence, byte shuffles between column/row rounds)
  • New std feature for runtime SIMD level detection via LazyLock;
    without it, level is determined at compile time
  • dudect-bencher constant-time verification example (ctbench)

Benchmarked on i7-8700B (AVX2), Salsa20/20:

Size Before After Speedup
16B 372 MB/s 372 MB/s 1.0x
256B 533 MB/s 579 MB/s 1.1x
1 KiB 537 MB/s 1,855 MB/s 3.5x
16 KiB 542 MB/s 1,949 MB/s 3.6x

Add opt-in SIMD backends (`simd` feature) that process 4 blocks
(SSE2/NEON) or 8 blocks (AVX2) in parallel, plus a diagonal
single-block path for HSalsa20 and tail processing. The `std`
feature implies `simd` and adds runtime SIMD level detection via
LazyLock. Without `simd`, the soft backend is used as before and
the MSRV stays at 1.85.

Backend4 (ParBlocksSize=U4) uses u32x4 for 128-bit SIMD.
Backend8 (ParBlocksSize=U8) uses the native-width vector for
256-bit SIMD, with chunked fallback for narrower levels.

HSalsa20 uses diagonal SIMD layout where each u32x4 holds one
role across all four quarter rounds, with byte shuffles to rotate
between column and row rounds.

Adds dudect constant-time verification example (ctbench).

Restricts --all-features CI test to stable (fearless_simd requires
rustc 1.89, above the crate MSRV).

Benchmarked on i7-8700B (AVX2), Salsa20/20 throughput:
  16B:  372 -> 372 MB/s (1.0x)
  256B: 533 -> 579 MB/s (1.1x)
  1KB:  537 -> 1855 MB/s (3.5x)
  16KB: 542 -> 1949 MB/s (3.6x)
@paddor

paddor commented Jul 17, 2026

Copy link
Copy Markdown
Author

@tarcieri This should be ready for review. Sorry about the new simd feature. Otherwise I'd have had to bump MSRV to 1.89. You decide.

Closes #50.

@newpavlov

Copy link
Copy Markdown
Member

We generally aim to minimize third-party dependencies. I would strongly prefer to have a proper self-contained intrinsics-based implementation instead.

@tarcieri

tarcieri commented Jul 17, 2026

Copy link
Copy Markdown
Member

Yeah, we generally eschew crate dependencies for this sort of thing beyond our own cpufeatures crate for no_std-friendly CPU feature detection, even if it results in duplication of the SIMD backends, though ideally we could use a stable core::simd in the future.

ARX algorithms like Salsa/ChaCha in particular use a very limited number of operations (literally the three add-rotate-xor of ARX).

Before looping in a crate dependency I'd be curious to see what is possible with auto-vectorization alone, just by using #[target_feature] annotated "thunk" functions similar to what we do in argon2.

The multiversion crate provides a similar strategy though before going down that road I'd be curious to see what auto-vectorization alone can accomplish.

@paddor

paddor commented Jul 17, 2026

Copy link
Copy Markdown
Author

Naive auto-vectorization performs worse because of register spills. I'll follow the the chacha20 example and do the diagonal layout trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants